module sram_wrap #( 
parameter DEPTH = 4096, 
parameter DATA_W = 32, 
// DO NOT MODIFY FOLLOWING DERIVATIVE PARAMETERS ! 
parameter ADDR_W = $clog2(DEPTH) 
)( 
input logic clk, 
input logic rst_n, 
input logic [15:0] mem_ctrl, 
input logic [15:0] mem_dft, 
input logic [15:0] mem_lp, 
input logic scan_en, 
input logic cs, 
input logic wr, // 1'b1: write, 1'b0: read 
input logic [ADDR_W-1:0] addr, 
input logic [DATA_W-1:0] wdata, 
input logic [DATA_W-1:0] wen, 
output logic [DATA_W-1:0] rdata 
);


  //web, write enable, active low
  wire web = ~wr;
  //ceb: chip enable, active low
  wire ceb = ~cs;


  if (( DEPTH == 128) & (DATA_W == 56)) begin: gen_sram_128w_59b
  logic [6:0] addr_temp;
  logic [58:0] wdata_temp;
  logic [58:0] bweb_temp;
  logic [58:0] rdata_temp;
    assign  addr_temp = addr;
    assign  wdata_temp = {3'b000,wdata};
    assign  bweb_temp = {3'b111,~wen};
    assign  rdata = rdata_temp[55:0];

  TEM5N28HPCPLVTA128X59M4SWSO sram 
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp[6:0]),
      .D    (wdata_temp[58:0]),
      .BWEB (bweb_temp[58:0]),
      .Q    (rdata_temp[58:0]),
      .WEB  (web),
      .CEB  (ceb),
      .CLK  (clk)
    );
  end







  else if (( DEPTH == 8192) & (DATA_W == 72)) begin: gen_sram_2048w_36b_8192_72
  logic [10:0] addr_temp;
  logic [71:0] wdata_temp;
  logic [71:0] bweb_temp;
  logic [71:0] rdata_temp[3:0];
  logic [3:0] web_temp;
  logic [3:0] ceb_temp;
  logic       read_en;
  logic [1:0] addr_top_q;

  assign addr_temp  = addr[10:0];
  assign wdata_temp = wdata;
  assign bweb_temp  = ~wen;
  assign read_en    = cs & ~wr;
  always @(posedge clk)
  if (read_en)
    addr_top_q <= addr[12:11];

  assign rdata = 
        (addr_top_q ==2'b11) ? rdata_temp[3] :
        (addr_top_q ==2'b10) ? rdata_temp[2] :
        (addr_top_q ==2'b01) ? rdata_temp[1] :
                               rdata_temp[0];

  for (genvar i=0; i<4; i++) begin: gen_sram_2048w_36b_8192_72_subblock
    assign  web_temp[i] = ~(wr & (addr[12:11]==i[1:0]));  
    assign  ceb_temp[i] = ~(cs & (addr[12:11]==i[1:0]));
    TEM5N28HPCPLVTA2048X36M8SWSO sram_0
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp[35:0]),
      .BWEB (bweb_temp[35:0]),
      .Q    (rdata_temp[i][35:0]),
      .WEB  (web_temp[i]),
      .CEB  (ceb_temp[i]),
      .CLK  (clk)
    );
    TEM5N28HPCPLVTA2048X36M8SWSO sram_1
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp[71:36]),
      .BWEB (bweb_temp[71:36]),
      .Q    (rdata_temp[i][71:36]),
      .WEB  (web_temp[i]),
      .CEB  (ceb_temp[i]),
      .CLK  (clk)
    );
  end
  end


  ////////////////////////////////////////////////////////////////////////////
  //                      tcu -> ecc_dtcm0 ecc_dtcm1 ecc_vtcm
  ////////////////////////////////////////////////////////////////////////////

  else if (( DEPTH == 8192) & (DATA_W == 39)) begin: gen_sram_2048w_40b_8192_39
  logic [10:0] addr_temp;
  logic [39:0] wdata_temp;
  logic [39:0] bweb_temp;
  logic [39:0] rdata_temp[3:0];
  logic [3:0] web_temp;
  logic [3:0] ceb_temp;
  logic       read_en;
  logic [1:0] addr_top_q;

  assign addr_temp  = addr[10:0];
  assign wdata_temp = {1'b0,wdata};
  assign bweb_temp  = {1'b1,~wen};
  assign read_en    = cs & ~wr;
  always @(posedge clk)
  if (read_en)
    addr_top_q <= addr[12:11];

  assign rdata = 
        (addr_top_q ==2'b11) ? rdata_temp[3][38:0] :
        (addr_top_q ==2'b10) ? rdata_temp[2][38:0] :
        (addr_top_q ==2'b01) ? rdata_temp[1][38:0] :
                               rdata_temp[0][38:0];

  for (genvar i=0; i<4; i++) begin: gen_sram_2048_40b_8192_39_subblock
    assign  web_temp[i] = ~(wr & (addr[12:11]==i[1:0]));  
    assign  ceb_temp[i] = ~(cs & (addr[12:11]==i[1:0]));
    TEM5N28HPCPLVTA2048X40M8SWSO sram
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp),
      .BWEB (bweb_temp),
      .Q    (rdata_temp[i]),
      .WEB  (web_temp[i]),
      .CEB  (ceb_temp[i]),
      .CLK  (clk)
    );
  end
  end

////////////////////////////////////////////////////////////////////////////
//                  64KB:    tcu -> noecc_itcm
////////////////////////////////////////////////////////////////////////////

  else if (( DEPTH == 8192) & (DATA_W == 64)) begin: gen_sram_2048w_32b_8192_64
  logic [10:0] addr_temp;
  logic [63:0] wdata_temp;
  logic [63:0] bweb;
  logic [3:0][63:0] rdata_temp ;
  logic [3:0] web;
  logic [3:0] ceb;
  logic        read_en;
  logic [1:0]   addr_top_q;
    assign  addr_temp = addr[10:0];
    assign  wdata_temp = wdata[63:0];

   // current cycle has valid read operation
   assign read_en = cs & ~wr;
   always @(posedge clk)
    if (read_en) //if current cycle has valid read operation, flop address upper bits to select read data next cycle 
      addr_top_q <= addr[12:11];
  
    assign bweb = {~wen[63:0]};

   assign  rdata = 
        (addr_top_q ==2'b11) ? rdata_temp[3] :
        (addr_top_q ==2'b10) ? rdata_temp[2] :
        (addr_top_q ==2'b01) ? rdata_temp[1] :
                               rdata_temp[0];


    for(genvar i=0; i<4; i++) begin

    assign  web[i] = ~(wr & (addr[12:11]==i[1:0]));  

    assign  ceb[i] = ~(cs & (addr[12:11]==i[1:0]));

      // low 32bits banks 
     TEM5N28HPCPLVTA2048X32M8SWSO sram_low 
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp[31:0]),
      .BWEB (bweb[31:0]),
      .Q    (rdata_temp[i][31:0]),
      .WEB  (web[i]),
      .CEB  (ceb[i]),
      .CLK  (clk)
    );
     // high 32bits banks 
     TEM5N28HPCPLVTA2048X32M8SWSO sram_high 
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp[63:32]),
      .BWEB (bweb[63:32]),
      .Q    (rdata_temp[i][63:32]),
      .WEB  (web[i]),
      .CEB  (ceb[i]),
      .CLK  (clk)
    );
    end
  end  //gen_sram_2048w_32b_8192_64
  


////////////////////////////////////////////////////////////////////////////
//              64KB:  tcu -> noecc_dtcm0 noecc_dtcm1 noecc_vtcm
////////////////////////////////////////////////////////////////////////////

else if (( DEPTH == 8192) & (DATA_W == 32)) begin: gen_sram_2048w_32b_8192_32
  logic [10:0] addr_temp;
  logic [31:0] wdata_temp;
  logic [31:0] bweb ;
  logic [3:0][31:0] rdata_temp  ;
  logic [3:0] web;
  logic [3:0] ceb;
  logic        read_en;
  logic [1:0]   addr_top_q;
    assign  addr_temp = addr[10:0];
    assign  wdata_temp = wdata[31:0];

   // current cycle has valid read operation
   assign read_en = cs & ~wr;
   always @(posedge clk)
    if (read_en) //if current cycle has valid read operation, flop address upper bits to select read data next cycle 
      addr_top_q <= addr[12:11];

   assign  bweb = {~wen[31:0]};

   assign  rdata = 
        (addr_top_q ==2'b11) ? rdata_temp[3] :
        (addr_top_q ==2'b10) ? rdata_temp[2] :
        (addr_top_q ==2'b01) ? rdata_temp[1] :
                               rdata_temp[0];


    for(genvar i=0; i<4; i++) begin

   
    assign  web[i] = ~(wr & (addr[12:11]==i[1:0]));  

    assign  ceb[i] = ~(cs & (addr[12:11]==i[1:0]));

     TEM5N28HPCPLVTA2048X32M8SWSO sram_0 
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp[31:0]),
      .BWEB (bweb),
      .Q    (rdata_temp[i]),
      .WEB  (web[i]),
      .CEB  (ceb[i]),
      .CLK  (clk)
    );
    end
  end  //gen_sram_2048w_32b_8192_32






else if (( DEPTH == 4096) & (DATA_W == 64)) begin: gen_sram_2048w_32b_4096_64
  logic [10:0] addr_temp;
  logic [63:0] wdata_temp;
  logic [31:0] bweb_0;
  logic [31:0] bweb_1;
  logic [63:0] rdata_0;
  logic [63:0] rdata_1;
  logic        web_0;
  logic        web_1;
  logic        ceb_0;
  logic        ceb_1;
  logic        read_en;
  logic        addr_top_q;
    assign  addr_temp = addr[10:0];
    assign  wdata_temp = wdata[63:0];

    assign  bweb_0 = {~wen[31:0]};
    assign  bweb_1 = {~wen[63:32]};

    assign  web_0 = ~(wr & ~addr[11]);  
    assign  web_1 = ~(wr & addr[11]);

    assign  ceb_0 = ~(cs & ~addr[11]);
    assign  ceb_1 = ~(cs & addr[11]);
    // current cycle has valid read operation
    assign read_en = cs & ~wr;
   always @(posedge clk)
    if (read_en) //if current cycle has valid read operation, flop address upper bits to select read data next cycle 
      addr_top_q <= addr[11];

    assign  rdata = addr_top_q ? rdata_1 : rdata_0 ;

    TEM5N28HPCPLVTA2048X32M8SWSO sram_0_0 
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp[31:0]),
      .BWEB (bweb_0),
      .Q    (rdata_0[31:0]),
      .WEB  (web_0),
      .CEB  (ceb_0),
      .CLK  (clk)
    );

 TEM5N28HPCPLVTA2048X32M8SWSO sram_0_1 
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp[63:32]),
      .BWEB (bweb_1),
      .Q    (rdata_0[63:32]),
      .WEB  (web_0),
      .CEB  (ceb_0),
      .CLK  (clk)
    );

   TEM5N28HPCPLVTA2048X32M8SWSO sram_1_0 
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp[31:0]),
      .BWEB (bweb_0),
      .Q    (rdata_1[31:0]),
      .WEB  (web_1),
      .CEB  (ceb_1),
      .CLK  (clk)
    );

 TEM5N28HPCPLVTA2048X32M8SWSO sram_1_1 
      (.SLP  (1'b0),
      .SD   (1'b0),
      .A    (addr_temp),
      .D    (wdata_temp[63:32]),
      .BWEB (bweb_1),
      .Q    (rdata_1[63:32]),
      .WEB  (web_1),
      .CEB  (ceb_1),
      .CLK  (clk)
    );
    
  end

endmodule 